package br.ufrj.dcc.ad.graphics;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.util.Log;

import br.ufrj.dcc.ad.log.LoggerFactory;

public class JFreeChartFacade {
	
	private static Logger logger = LoggerFactory.getLogger(LoggerFactory.Type.TIMED_STDOUT);
	
	/***
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param name
	 * @param valueSeparator
	 * @param inputFilename
	 * @param cdf
	 * @return
	 */
	public static boolean plotarGrafico(String title, String xAxisLabel,
		String yAxisLabel, String name, String valueSeparator, String inputFilename, boolean cdf) {
		
		boolean retorno = false;
		
		retorno = JFreeChartFacade.plotar(title, xAxisLabel, yAxisLabel, name, valueSeparator, inputFilename, cdf);
		
		if(retorno) {
			Log.info("Sucesso ao plotar Grafico");
		}
		
		return retorno;
	}
	
	/***
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param name
	 * @param valueSeparator
	 * @param graphicSeparator
	 * @param size
	 * @param inputFilename
	 * @param cdf
	 * @return
	 */
	public static boolean plotarGraficos(String title, String xAxisLabel, String yAxisLabel,
		String name, String valueSeparator, String graphicSeparator, int size, String inputFilename, boolean cdf) {
		
		boolean retorno = false;
		
		retorno = JFreeChartFacade.plotar(title, xAxisLabel, yAxisLabel, name, valueSeparator, graphicSeparator, size, inputFilename, cdf);
		
		if(retorno) {
			logger.info("Sucesso ao plotar Graficos");
		}
		
		return retorno;
	}
	
	public static boolean plotarGraficosIndexados(String title, String xAxisLabel, String yAxisLabel,
		String name, String valueSeparator, String graphicSeparator, int size, String inputFilename, String regex, boolean cdf) {
		
		boolean retorno = false, retornoCumulativo = true;
		String formatedFilename = null;
		
		for(int i = 0; i < size; ++i) {
			formatedFilename = inputFilename.replace(regex, Integer.toString(i));
			retorno = JFreeChartFacade.plotarGrafico(title.concat(Integer.toString(i)), xAxisLabel, yAxisLabel, name, valueSeparator, formatedFilename, cdf);
			retornoCumulativo = retornoCumulativo && retorno;
		}
		
		if(retornoCumulativo) {
			logger.info("Sucesso ao plotar Graficos");
		}
		
		return retornoCumulativo;
	}
	
	/***
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param name
	 * @param valueSeparator
	 * @param graphicSeparator
	 * @param size
	 * @param inputFilename
	 * @param cdf
	 * @return
	 */
	public static boolean plotarGraficosMesmaImagem(String title, String xAxisLabel, String yAxisLabel,
			String name, String valueSeparator, String graphicSeparator, int size, String inputFilename, boolean cdf) {
		
		try {
			Scanner reader = new Scanner(new FileInputStream(inputFilename));
			XYSeriesCollection collection = new XYSeriesCollection();
			
			String linha = null;
			boolean first = true;
			
			for(int i = 0; i < size; ++i) {
				// Procura pelo separador de grafico, no caso Rodada X
				while(first && reader.hasNext()) {
					linha = reader.nextLine().trim();
					if(linha.equals(graphicSeparator)) {
						break;
					}
				}
				collection.addSeries(read(reader, name + i, valueSeparator, graphicSeparator, cdf));
				first = false;
			}
			
			try {
				String nomeArquivo = title.replaceAll(" ", "_").concat(".png");
				JFreeChartFacade.renderizar(collection, title, xAxisLabel, yAxisLabel, nomeArquivo, 800, 600);
				logger.info(nomeArquivo  + " gerada");
			} catch (IOException e) {
				Log.error("Erro ao plotar", e);
				return false;
			}
			
			return true;
		} catch (FileNotFoundException e) {
			return false;
		}
	}
	
	/**
	 * @param pontos
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param name
	 * @param cdf
	 * @return
	 */
	public static boolean plotarGrafico(List<Ponto> pontos, String title, String xAxisLabel, String yAxisLabel,
			String name, boolean cdf) {
		
		XYSeries series = new XYSeries(name);
		
		for(Ponto ponto : pontos) {
			series.add(ponto.x, ponto.y);
		}
		
		try {
			String nomeArquivo = title.replaceAll(" ", "_").concat(".png");
			JFreeChartFacade.renderizar(series, title, xAxisLabel, yAxisLabel, nomeArquivo, 640, 480);
			logger.info(nomeArquivo  + " gerada");
		} catch (IOException e) {
			logger.error("Erro ao plotar", e);
			return false;
		}
		
		return true;
	}
	
	/***
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param name
	 * @param valueSeparator
	 * @param graphicSeparator
	 * @param size
	 * @param inputFilename
	 * @param cdf
	 * @return
	 */
	private static boolean plotar(String title, String xAxisLabel, String yAxisLabel,
		String name, String valueSeparator, String graphicSeparator, int size, String inputFilename, boolean cdf) {
		
		try {
			Scanner reader = new Scanner(new FileInputStream(inputFilename));
			XYSeries series = null;
			String linha = null;
			
			while(reader.hasNext()) {
				linha = reader.nextLine().trim();
				if(linha.equals(graphicSeparator)) {
					break;
				}
			}
			
			for(int i = 0; i < size; ++i) {
				// Procura pelo separador de grafico, no caso Rodada X
				series = read(reader, name, valueSeparator, graphicSeparator, cdf);
				
				try {
					String nomeArquivo = title.replaceAll(" ", "_").concat(Integer.toString(i)).concat(".png");
					JFreeChartFacade.renderizar(series, title, xAxisLabel, yAxisLabel, nomeArquivo, 640, 480);
					logger.info(nomeArquivo  + " gerada");
				} catch (IOException e) {
					logger.error("Erro ao plotar", e);
					return false;
				}
			}
			
			return true;
		} catch (FileNotFoundException e) {
			logger.error("Erro ao plotar", e);
			return false;
		}
	}
	
	/***
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param name
	 * @param valueSeparator
	 * @param inputFilename
	 * @param cdf
	 * @return
	 */
	private static boolean plotar(String title, String xAxisLabel, String yAxisLabel, String name,
			String valueSeparator, String inputFilename, boolean cdf) {
		
		try {
			Scanner reader = new Scanner(new FileInputStream(inputFilename));
			XYSeries series = new XYSeries(name);
			
			series = read(reader, name, valueSeparator, null, cdf);
			
			try {
				String nomeArquivo = title.replaceAll(" ", "_").concat(".png");
				JFreeChartFacade.renderizar(series, title, xAxisLabel, yAxisLabel, nomeArquivo, 800, 600);
			} catch (IOException e) {
				logger.error("Erro ao plotar", e);
				return false;
			}
			
			return true;
		} catch (FileNotFoundException e) {
			logger.error("Erro ao plotar", e);
			return false;
		}
	}
	
	/***
	 * @param reader
	 * @param name
	 * @param valueSeparator
	 * @param graphSeparator
	 * @param cdf
	 * @return
	 */
	private static XYSeries read(Scanner reader, String name, String valueSeparator, String graphSeparator, boolean cdf) {
		String linha;
		String[] splitted;
		Double x = null, y = null, sum = 0.0;
		
		XYSeries series = new XYSeries(name);
		
		while(reader.hasNext()) {
			linha = reader.nextLine().trim();
			splitted = linha.split(valueSeparator);
			if(splitted.length > 1) {
				try {
					x = Double.parseDouble(splitted[0].trim());
					y = Double.parseDouble(splitted[1].trim());
					if(cdf) {
						sum += y;
						series.add(x, sum);
					} else {
						series.add(x, y);
					}
				} catch(NumberFormatException e) {}
			} else {
				if(splitted[0].equals(graphSeparator)) {
					break;
				}
			}
		}
		
		return series;
	}
	
	/***
	 * 
	 * @param series
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param path
	 * @param width
	 * @param height
	 */
	private static void renderizar(XYSeries series, String title, String xAxisLabel, String yAxisLabel,
			String path, Integer width, Integer height) throws IOException {
		
		XYSeriesCollection dataset = new XYSeriesCollection(series);
		
		JFreeChart chart = ChartFactory.createXYLineChart(null, xAxisLabel, yAxisLabel, dataset, PlotOrientation.VERTICAL,
			false, true, true);
		
		BufferedImage imagem = chart.createBufferedImage(width, height);
		
		File f = new File(path);
		if(f.exists()) f.delete();
		
		ImageIO.write(imagem, "png", f);
	}
	
	/**
	 * @param collection
	 * @param title
	 * @param xAxisLabel
	 * @param yAxisLabel
	 * @param path
	 * @param width
	 * @param height
	 * @throws IOException
	 */
	private static void renderizar(XYSeriesCollection collection, String title, String xAxisLabel, String yAxisLabel,
			String path, Integer width, Integer height) throws IOException {
		
		JFreeChart chart = ChartFactory.createXYLineChart(null, xAxisLabel, yAxisLabel, collection, PlotOrientation.VERTICAL,
			true, true, true);
		
		BufferedImage imagem = chart.createBufferedImage(width, height);
		
		File f = new File(path);
		if(f.exists()) f.delete();
		
		ImageIO.write(imagem, "png", f);
	}
}
